<?
/**
 * $Id: DB.class.php 982 2008-07-31 15:25:34Z dakl $
 * Interfejs polaczenia z baza v2.2
 *
 */
interface DBConnection {
	public function Prepare($query);
	public function Execute($query);
}
/**
 * Interfejs danych w bazie
 *
 */
interface DBStatement {
	public function Execute();
	public function BindParam($key, $value);
	public function FetchRow();
	public function FetchAssoc();
	public function FetchAllAssoc();
}
/**
 * Klasa do obslugi bazy mysql
 *
 */
class DBMysql implements DBConnection {
	protected $user;
	protected $pass;
	protected $dbHost;
	protected $dbName;
	protected $dbh;
	protected $characterset = 'utf8';

	/**
     * Konstruktor klasy
     *
     * @param string $user
     * @param string $pass
     * @param string $dbHost
     * @param string $dbName
     */
	public function __construct($user, $pass, $dbHost, $dbName) {
		$this->user = $user;
		$this->pass = $pass;
		$this->dbHost = $dbhost;
		$this->dbName = $dbname;
	}
	/*Nawiazywanie polaczenia z baza*/
	protected function Connect() {
		Profiler::log('mysqlStart', '', microtime());
		if(!Core::GetAppSafeMode()) {
			try {
				$this->DbConnect();
				$this->SelectDb();
				$this->SetCharacterset();
			} catch (Exception $e) {
				MFLog::Fatal("Line: ".$e->getLine()." Message: ".$e->getMessage()." Referer: ".getenv('HTTP_REFERER'));
				MFLog::Error("Switching app to safe mode");
				Core::SetAppSafeMode();
			}
		}

	}

	protected function DbConnect() {
		$this->dbh = @mysql_connect($this->dbHost, $this->user, $this->pass);
		if(empty($this->dbh)) {
			throw new MysqlException('Cannot connect to database!');
		}
	}

	protected function SelectDb() {
		if(!mysql_select_db($this->dbName, $this->dbh)) {
			throw new MysqlException('Cannot select database!');
		}
	}

	public function tableExists($tableName) {
		$sql = "SHOW TABLES FROM ".$this->dbName;
		$result = mysql_query($sql);
		while ($row = mysql_fetch_row($result)) {
		if ($row['0'] == $tableName) {
			return TRUE;
		}
	}
	return FALSE;
	}

	protected function SetCharacterset() {
		mysql_query("SET CHARACTER SET ".$this->characterset);
		mysql_query("SET NAMES '".$this->characterset."'");
		mysql_query("SET CHARACTER_SET_CLIENT = ".$this->characterset);
		mysql_query("SET character_set_results = ".$this->characterset);
		mysql_query("SET character_set_connection = ".$this->characterset);
		$time_diff = date('P',time());
		mysql_query("SET time_zone = '$time_diff'");

	}

	public function Escape($string) {

		if(Enviroment::CheckMagicQuotes()) {
			$return = mysql_real_escape_string(stripslashes($string));
		} else {
			$return = mysql_real_escape_string($string);
		}

		return $return;
	}

	/*Wykonanie zapytania*/
	public function Execute($query) {

		if(!$this->dbh) {
			$this->Connect();
		}
		MFLog::Debug($query);
		$startTime = microtime();
		$ret = 'unexecuted';
		if($this->dbh) {
			$ret = mysql_query($query);
		}
		$endTime = microtime();
		Profiler::log('mysql', $query, abs($endTime-$startTime));

		
		if(!$ret && $ret!='unexecuted') {
			throw new MysqlException(mysql_error().$query);
		}
		else {
			$stmt = new DBMysqlStatement($this->dbh, $query);
			$stmt->result = $ret;
			return $stmt;
		}
	}
	/*Przygotowanie zapytania zwraca obiekt klasy DBMysqlStatement*/
	public function Prepare($query) {
		if(!$this->dbh) {
			$this->Connect();
		}
		return new DBMysqlStatement($this->dbh, $query);
	}

	public function Stat() {
		return mysql_stat($this->dbh);
	}

	/**
     * Rozpoczyna transakcje
     *
     */
	public function BeginTransaction() {
		if(!$this->dbh) {
			$this->Connect();
		}
		@mysql_query("START TRANSACTION ");
	}

	/**
     * Zartwierdza transakcje
     *
     */
	public function CommitTransaction() {
		if(!$this->dbh) {
			$this->Connect();
		}
		@mysql_query("COMMIT");
	}

	/**
     * Wycofuje transakcje
     *
     */
	public function Rollback() {
		if(!$this->dbh) {
			$this->Connect();
		}
		@mysql_query("ROLLBACK");
	}

	/**
     * Destruktor zamykajacy polaczenie
     *
     */
	public function __destruct() {
		if(isset($this->dbh) && is_resource($this->dbh)) {
			mysql_close($this->dbh);

			Profiler::log('mysqlEnd', '', microtime());

		}
	}
	public function GetDbh() {
		return $this->dbh;
	}

}

/**
 * Klasa implementujaca interfejs DBStatement dla mysqla
 *
 */
class DBMysqlStatement implements DBStatement {
	public $result;
	public $binds;
	public $query;
	public $dbh;
	private $cacheTime = 30;
	private $cacheFile;
	private $cachePath = DBCACHE_PATH;
	private $cacheEnable = DBCACHE_ENABLE;
	private $cacheQuery = false;

	/**
     * KOnstruktor klasy
     *
     * @param mysql $dbh
     * @param string $query
     */
	public function __construct($dbh, $query) {
		$this->query = $query;
		$this->dbh = $dbh;
		if(!$dbh) {
			Core::SetAppSafeMode();
			//throw new MysqlException("No db connection");

		}
	}

	public function freeResult() {
		mysql_free_result($this->result);
	}

	/**
     * Zwraca tresc zapytania
     *
     * @return unknown
     */
	public function GetQuery()
	{
		return $this->query;
	}
	/*Zamienia zmienne w zapytaniu na podane wartosci*/
	public function BindParam($ph, $pv) {
		$this->binds[$ph] = $pv;
		return $this;
	}
	/*Wykonanie zapytania*/
	public function Execute() {

		$binds = func_get_args();
		foreach($binds as $index => $name) {
			$this->binds[$index + 1] = $name;
		}
		$cnt = count($binds);
		$query = $this->query;

		if (count($this->binds)>0) {
			foreach ($this->binds as $ph => $pv) {
				
				$query = str_replace(":$ph", '\''.mysql_real_escape_string($pv).'\'', $query);
			}
		}
		MFLog::Debug(__FUNCTION__.' query: '.$query);
		if($this->dbh) {
			$startTime = microtime();
			$this->result = mysql_query($query);
			$endTime = microtime();
			Profiler::log('mysql', $query, abs($endTime-$startTime));
			if(!$this->result) {
				throw new MysqlException($query . "<br /><br />" . mysql_error());
			}
		}
		return $this;
	}
	/*Zwraca wiersz*/
	public function FetchRow() {
		if(!$this->result) {
			throw new MysqlException("Query failed");
		}
		$this->SetCacheFile($this->query.'FetchRow');

		if($this->cacheQuery==false) {
			$result = mysql_fetch_row($this->result);

		}

		else if ($this->cacheQuery==true && !$this->CacheCheck() && !Core::GetAppSafeMode()) {
			$result = mysql_fetch_row($this->result);

			$this->CacheWrite($result);
		} else {
			$result = $this->CacheRead();
		}

		return $result;
	}
	/*Zwraca wiersz jako tablice asocjacyjna*/
	public function FetchAssoc() {
		$this->SetCacheFile($this->query.'FetchAssoc');

		if($this->cacheQuery==false) {
			$result = mysql_fetch_assoc($this->result);

		}

		else if(($this->cacheQuery==true && !$this->CacheCheck() && !Core::GetAppSafeMode())) {
			$result = mysql_fetch_assoc($this->result);

			$this->CacheWrite($result);
		} else {
			$result = $this->CacheRead();
		}

		return $result;
	}
	/*Zwraca ca�y wynik jako tablica asocjacyjna*/
	public function FetchAllAssoc() {
		$this->SetCacheFile($this->query.'FetchAllAssoc');

		if($this->cacheQuery==false) {
			$result = array();

			while($row = $this->fetchAssoc()) {
				$result[] = $row;
			}
		}

		else if($this->cacheQuery==true && !$this->CacheCheck() && !Core::GetAppSafeMode()) {
			$result = array();
			$this->cacheQuery = false;
			while($row = $this->fetchAssoc()) {
				$result[] = $row;
			}
			$this->SetCacheFile($this->query.'FetchAllAssoc');
			$this->CacheWrite($result);
		} else {
			$result = $this->CacheRead();
		}

		return $result;

	}
	/*Zwraca ca�y wynik jako tablica asocjacyjna*/
	public function FetchAllRow() {
		$this->SetCacheFile($this->query.'FetchAllRow');



		if($this->cacheQuery==false) {
			$result = array();

			while($row = $this->fetchRow()) {
				$result[] = $row;
			}
		}

		else if($this->cacheQuery==true && !$this->CacheCheck() && !Core::GetAppSafeMode()) {
			$result = array();
			$this->cacheQuery = false;
			while($row = $this->fetchRow()) {
				$result[] = $row;
			}
			$this->SetCacheFile($this->query.'FetchAllRow');
			$this->CacheWrite($result);
		} else {
			$result = $this->CacheRead();
		}

		return $result;
	}
	/*Zwraca liczbe wierszy*/
	public function NumRows() {
		if(!$this->result) {
			throw new MysqlException("Query failed");
		}
		$this->SetCacheFile($this->query.'NumRows');


        if($this->cacheQuery==false) {
            $result = mysql_num_rows($this->result);
	    
        }



        else if($this->cacheQuery==true && !$this->CacheCheck() && !Core::GetAppSafeMode()) {
            $result = mysql_num_rows($this->result);
	    
            $this->CacheWrite($result);
        } else {
            $result = $this->CacheRead();
        }


		return $result;
	}



	/*Zwraca wiersz w postaci tablicy*/
	public function FetchArray() {
		
		if(!$this->result) {
			throw new MysqlException("Query failed");
		}
		$this->SetCacheFile($this->query.'FetchArray');




        if($this->cacheQuery==false) {
            $result = mysql_fetch_array($this->result);
	   
        }



        else if($this->cacheQuery==true && !$this->CacheCheck() && !Core::GetAppSafeMode()) {
            $result = mysql_fetch_array($this->result);
	    
            $this->CacheWrite($result);
        } else {
            $result = $this->CacheRead();
        }


		return $result;
	}
	/**
     * Zwraca id ostatnio zmienionego rekordu
     *
     * @return integer
     */
	public function GetInsertionId() {
		if(!$this->result) {
			throw new MysqlException("Query failed");
		}
		return mysql_insert_id();
	}

	/**
     * Zwraca liczb� zmienionych rekord�w w ostatnim zapytaniu modyfikuj�cym dane.
     *
     * @return integer
     */
	public function GetAffectedRows()
	{
		if(!$this->result) {
			throw new MysqlException("Query failed");
		}
		return mysql_affected_rows();

	}

	/**
     * Sprawdza czy zaoytanie jest cacheowane
     *
     * @return boolean
     */
	public function CacheCheck() {
		if($this->cacheEnable == false || ($this->cacheEnable == true && (is_file($this->cachePath.$this->cacheFile) && filemtime($this->cachePath.$this->cacheFile) > (time() - $this->cacheTime)))) {
			return true;
		} else {
			return false;
		}
	}

	/**
     * Zapisuje cache do pliku
     *
     * @param obj $result
     */
	public function CacheWrite($result) {
		if($this->cacheEnable != false) {
			$records = serialize($result);
			$fp = fopen($this->cachePath.$this->cacheFile, "w");
			fputs($fp, $records);
			fclose($fp);
			$this->cacheQuery = false;
		}

	}

	/**
     * Odczytuje cache z pliku
     *
     * @return obj
     */
	public function CacheRead() {
		if(is_file($this->cachePath.$this->cacheFile)) {
			$records = unserialize(file_get_contents($this->cachePath.$this->cacheFile));
			$this->cacheQuery = false;
			return $records;
		} else {
			throw new MysqlException('File does not exist: '.$this->cachePath.$this->cacheFile);
		}
	}

	/**
     * Uruchamia cacheowanie
     *
     * @param integer $time
     */
	public function CacheStart($time=null) {
		if($time!=null && $this->cacheEnable != false) {
			$this->cacheTime = $time;
		}
		if($this->cacheEnable != false)
		$this->cacheQuery = true;
		else
		$this->cacheQuery = false;

		return $this;
	}

	/**
     * Ustanawia nazw� pliku cache
     *
     * @param unknown_type $fileName
     */
	public function SetCacheFile($fileName) {
		$this->cacheFile=md5($fileName);
	}




}

/**
 * Klasa obslugi wynikow zapytan
 *
 */
class DBResult {
	protected $stmt;
	protected $result = array();
	private $rowIndex = 0;
	private $currIndex = 0;
	private $done = false;

	/**
     * Konstruktor
     *
     * @param DBStatement $stmt
     */
	public function __construct(DBStatement $stmt)
	{
		$this->stmt = $stmt;
	}
	/*Zwraca pierwszy rekord*/
	public function First()
	{
		if(!$this->result) {
			$this->result[$this->rowIndex++] = $this->stmt->FetchAssoc();
		}
		$this->currIndex = 0;
		return $this;
	}
	/*Zwraca ostatni rekord*/
	public function Last()
	{
		if(!$this->done) {
			array_push($this->result, $this->stmt->FetchAllAssoc());
		}
		$this->done = true;
		$this->currIndex = $this->rowIndex = count($this->result) - 1;
		return $this;
	}
	/*Zwieksza index i zwraca kolejny rekord*/
	public function Next()
	{
		if($this->done) {
			return false;
		}
		$offset = $this->currIndex + 1;
		if(!$this->result[$offset]) {
			$row = $this->stmt->FetchAssoc();
			if(!$row) {
				$this->done = true;
				return false;
			}
			$this->result[$offset] = $row;
			++$this->rowIndex;
			++$this->currIndex;
			return $this;
		}
		else {
			++$this->currIndex;
			return $this;
		}
	}
	/*Zmniejsza index i zwraca poprzedni wiersz*/
	public function Prev()
	{
		if($this->currIndex == 0) {
			return false;
		}
		--$this->currIndex;
		return $this;
	}

	/**
     * Getter dla pobieranych danych
     *
     * @param string $value
     * @return string
     */
	public function __get($value)
	{
		if(array_key_exists($value, $this->result[$this->currIndex])) {
			return $this->result[$this->currIndex][$value];
		}
	}
}

/**
 * Klasa oslonowa naszej bazy danych
 *
 */
class DBProd extends DBMysql {
	protected $user;
	protected $pass;
	protected $dbHost;
	protected $dbName;

	/**
     * Pusty konstruktor
     *
     */
	public function __construct() {

		$db = Config::Get('db');
		$this->dbHost = $db['prodHost'];
		$this->dbName = $db['prodDb'];
		$this->user = $db['prodUser'];
		$this->pass = $db['prodPass'];

	}



	public function GetDbh() {
		if(empty($this->dbh)) {
			$this->Connect();
		}
		return $this->dbh;
	}
}

class DBStat extends DBMysql {
	protected $user   = DBSTATUSER;
	protected $pass   = DBSTATPASS;
	protected $dbHost = DBSTATHOST;
	protected $dbName = DBSTATDB;

	/**
     * Pusty konstruktor
     *
     */
	public function __construct() {



	}



	public function GetDbh() {
		if(empty($this->dbh)) {
			$this->Connect();
		}
		return $this->dbh;
	}
}
